var modal = (function(){

    //弹出层ID数字
    var _modalID = 0;
    //setTimeout ID
    var _setTimeOutID = 0;
    //遮罩层元素ID
    var shadeID = "modal-shade";

    /**
     * 默认设置
     * @type {{container: null, content: null, millisecond: number, onclose: null, hasShade: boolean}}
     */
    var options = {};

    function optionsConstructor(opts){
        var defaults = {
            container: null,
            content: null,
            millisecond: 2000,
            hasShade: true,
            hasClose: false,
            autoClose: false,
            needRemove: false,
            onClose: null,
            noStyle: false,
            animation: true,
            open: {
                duration: 400,
                complete: null
            },
            close: {
                duration: 150,
                complete: null
            }
        }

        $.extend(defaults, opts)

        //设置开启或关闭动画效果
        if (!defaults.animation) defaults.open.duration = defaults.close.duration = 0;

        return defaults;
    }

    function modalInterface(){
        this.options = optionsConstructor();
        this.open = _open.call(this);
        this.close = _close.call(this);
        this.message = _message.call(this);
        this.loading = _loading.call(this);
    }

    /**
     * 创建新弹出层元素ID
     * @returns {string}
     * @private
     */
    var _createModalID = function(){
        return "modal" + (++_modalID);
    }

    /**
     * 创建弹出层容器
     * @returns {*|jQuery|HTMLElement}
     * @private
     */
    var _createModalWrap = function(){
        var $wrap = $('<div id="'+ _createModalID() +'" class="modal-wrapper" style="display: none;">' +
            '   <div class="modal-container">' +
            '       <div class="modal-content"></div>' +
            '   </div>' +
            '</div>');
        _addRemoveClass($wrap);
        return $wrap;
    }

    /**
     * 获取当前弹出层元素ID
     * @returns {string}
     * @private
     */
    var _getModalID = function(){
        return "modal" + _modalID;
    }

    /**
     * 获取当前弹出层元素
     * @returns {*|jQuery|HTMLElement}
     * @private
     */
    var _getModalEl = function(){
        var $modal;
        if (options.container != null){
            $modal = options.IsWrapped ? $(options.container).closest(".modal-wrapper") : $modal = $(options.container);
        }else{
            $modal = $("#" + _getModalID())
        }
        return $modal;
    }

    /**
     * 获取当前弹出层内容容器
     * @param $modal
     * @returns {*}
     * @private
     */
    var _getContentEl = function (){
        return _getModalEl().find(".modal-content");
    }

    var _appendStyle = function(){
        var $head = $(document.head);
        if ($("#modal-style").length == 0){
            $head.prepend(
                    '<style id="modal-style">' +
                    '.modal-wrapper{top:0; left:0; right:0; bottom:0; position:absolute; margin:auto; text-align:center; z-index:9999; width:100%; box-sizing:border-box; padding:0;}' +
                    '.modal-container{display:inline-block; padding:20px; position:relative;}' +
                    '.modal-container-nostyle{display:inline-block; position:relative;}' +
                    '.modal-close{color:inherit; font-size:30px; position:absolute; top:-30px; right:0; width:30px; height:30px; line-height:30px; cursor:pointer;}' +
                    '.shade{background-color:#000; opacity:0.6; top:-200%; bottom:0; left:-200%; right:0; height:500%; width:500%; position:fixed; z-index:9998;}' +
                    '</style>'
            );
        }
    }

    var _createCloseButton = function($modal){
        var $close = $('<div class="modal-close">×</div>');
        $modal.find(".modal-container").prepend($close);
        $close.click(function(){
            modal.close({
                container: $modal
            });
        });
    }

    var _wrapElement = function($el){
        $el.wrap(
                '<div id="'+ _createModalID() +'" class="modal-wrapper" style="display:none;">' +
                '<div class="modal-container">' +
                '<div class="modal-content">'
        ).show();
        var $modal = _getModalEl();
        _addRemoveClass($modal);
        $modal.parents(":hidden").show().attr("data-sign", "modal-show");
    }

    var _unwrapElement = function($el){
        $el.unwrap("<div class='modal-content'>")
            .unwrap("<div class='modal-container'>")
            .unwrap("<div class='modal-wrapper'>");
        $("[data-sign='modal-show']").hide();
    }

    var _addRemoveClass = function($modal){
        if (options.needRemove) $modal.addClass("modal-need-remove")
    }

    /**
     * 创建弹出层结构
     * @returns {*}
     * @private
     */
    var _createModal = function(){

        var $modal;
        _appendStyle();

        if (options.container){
            var $container = $(options.container);
            if (!$container.hasClass("modal-wrapper") && $container.find(".modal-wrapper").length < 1){
                _wrapElement($container);
                options.IsWrapped = true;
            }
            $modal = _getModalEl();
            if (!options.autoClose && options.hasClose) _createCloseButton($modal);
        }else{
            $modal = _createModalWrap();
            $(document.body).append($modal);
            _getContentEl().html(options.content);
        }

        //如果不需要modal容器的样式，移除容器样式
        if (options.noStyle) $modal.find(".modal-container").removeClass("modal-container").addClass("modal-container-nostyle");

        //设置弹出层高度，绝对定位全屏居中需要设置元素高度，否则不生效
        $modal.height(_getHeight($modal, options.noStyle ? ".modal-content" : ".modal-container"));

        return $modal;
    }

    /**
     * 添加遮罩层元素
     * @private
     */
    var _appendShade = function(){
        $(document.body).prepend('<div id="'+ shadeID +'" class="shade"></div>');
    }

    /**
     * 移除遮罩层元素
     * @private
     */
    var _removeShade = function(){
        $("#" + shadeID).remove();
    }

    /**
     * 获取隐藏元素真实高度
     * @param $el                   最外层被隐藏的容器
     * @param childrenSelector      要选择的子元素的选择器，可不传，不传则默认获取$el的高度
     * @returns {*}
     * @private
     */
    var _getHeight = function ($el, childrenSelector) {
        var height, $target;
        var css_class = "get-height";
        $(document.head).append("<style id='get-height-style'>." + css_class + "{position: absolute !important;visibility: hidden !important;display: block !important;}</style>");
        $el.addClass(css_class);
        $target = childrenSelector ? $el.find(childrenSelector) : $el;
        var height = $target.height();
        var paddingTop = parseInt($target.css("padding-top").replace("px"));
        var paddingBottom = parseInt($target.css("padding-bottom").replace("px"));
        var marginTop = parseInt($target.css("margin-top").replace("px"));
        var marginBottom = parseInt($target.css("margin-bottom").replace("px"));
        var outerHeight = height + paddingTop + paddingBottom + marginTop + marginBottom;
        height = height == outerHeight ? height : outerHeight;
        $el.removeClass(css_class);
        $("#get-height-style").remove();
        return height;
    }

    /**
     * 打开弹出层
     * @param userOptions
     * @returns {*}
     * @private
     */
    var _open = function(userOptions){
        //初始化设置参数
        options = optionsConstructor(userOptions);
        //添加遮罩层
        options.hasShade && _appendShade();
        //添加弹出层dom
        var $modal = _createModal();
        //显示弹出层
        $modal.show().animate("bounceIn", {
            duration: options.open.duration,
            complete: options.open.complete
        });
        //设置自动关闭
        options.autoClose && _timeoutClose(userOptions);
        return $modal;
    }

    /**
     * 关闭弹出层
     * @param userOptions
     * @private
     */
    var _close = function(userOptions){

        if (!options.container && !options.content) return;

        options = $.extend(options, userOptions);

        //获取当前弹出层
        var $modal, $el, _duration = 150;
        $modal = options.container != null ? $(options.container) : _getModalEl();
        if (options.IsWrapped){
            $el = $modal;
            $modal = $el.parents(".modal-wrapper");
        }
        //关闭弹出层
        $modal.animate("bounceOut", {
            duration: options.close.duration,
            complete: function(){

            }
        });

        setTimeout(function(){
            closeAnimationComplete()
        }, options.close.duration)

        function closeAnimationComplete(){
            modal.singleton = 0;
            //移除遮罩层
            _removeShade();
            //隐藏元素
            $modal.hide();
            //执行onclose事件
            options.onClose && options.onClose($modal);
            //如果元素是被wrap的，则在关闭之后要unwrap
            $(".modal-need-remove").remove();
            if (options.IsWrapped){
                _unwrapElement($el);
            }
            //执行关闭的complete事件
            if (options) {
                options.complete && options.complete($modal);
            }
        }
    }

    /**
     * 弹出层消息
     * @param userOptions
     * @private
     */
    var _message = function(userOptions){
        //初始化参数
        userOptions = typeof(userOptions) == "string" ? {content:userOptions} : userOptions;
        //消息方法不能传递容器
        if (userOptions.container){
            alert("message方法不能传递container，请使用open");
            return;
        }
        //message方法默认自动关闭
        userOptions.autoClose = typeof(userOptions.autoClose) == "undefined" ? true : userOptions.autoClose;
        //打开弹出层
        var $modal = _open(userOptions);
        //设置关闭事件，用于移除弹出层dom
        options.onClose = function($modal){
            userOptions.onClose && userOptions.onClose($modal);
            $modal.remove();
        }
    }

    //超时关闭
    var _timeoutClose = function(userOptions){
        clearTimeout(_setTimeOutID);
        _setTimeOutID = setTimeout(function(){
            _close(userOptions);
        }, options.millisecond);
    }

    var _loading = function(){
        var loadingHtml = '<div class="loading modal-loading-box">';
        for (var i=0; i<6; i++){
            loadingHtml += '<div class="modal-loading-block">' +
                '<div class="modal-loading-line"></div>' +
                '<div class="modal-loading-line"></div>' +
                '</div>';
        }
        loadingHtml += '</div>';

        var userOptions = {
            content: loadingHtml,
            autoClose: false,
            noStyle: true,
            animation: false
        }
        _open(userOptions);
    }

    return {
        open: _open,
        close: _close,
        message: _message,
        defaults: optionsConstructor,
        loading: _loading
    }
})();

$.fn.modal = function(userOptions){
    if (typeof(userOptions) == "undefined") userOptions = modal.defaults();
    userOptions.container = this;
    modal.open(userOptions);
}